#ifndef _LINUX_DO_DEV_H
#define _LINUX_DO_DEV_H

#include <linux/types.h>
#include "drv_pcie.h"
#include "drv_pcie_irq.h"
#include "drv_cdev.h"

/* 硬件状态，高电平吸合，低电平断开 */

struct pulse_t {
    u16 high;       /* 脉冲高电平时间, ms */
    u16 cycle;      /* 脉冲周期, ms */
    u32 num;        /* 脉冲个数 */
};

/* IOCTL 命令定义 */
#define IOCTL_DO_MAGIC                  'P'                                         /* 标识设备驱动 */
#define IOCTL_DO_SET_ALL_LEVEL          _IOW(IOCTL_DO_MAGIC, 1, u32)                /* 配置 DO 所有通道电平 */
#define IOCTL_DO_GET_ALL_LEVEL          _IOR(IOCTL_DO_MAGIC, 2, u32)                /* 获取 DO 所有通道电平 */
#define IOCTL_DO_SET_MODE               _IOW(IOCTL_DO_MAGIC, 3, u8)                 /* 配置 DO 模式 */
#define IOCTL_DO_SET_TIMEOUT_STA        _IOW(IOCTL_DO_MAGIC, 4, u8)                 /* 配置 DO 吸合超时状态 */
#define IOCTL_DO_SET_TIMEOUT            _IOW(IOCTL_DO_MAGIC, 5, u8)                 /* 配置 DO 吸合超时时间 */
#define IOCTL_DO_SET_LEVEL              _IOW(IOCTL_DO_MAGIC, 6, u8)                 /* 配置 DO 电平 */
#define IOCTL_DO_GET_LEVEL              _IOW(IOCTL_DO_MAGIC, 7, u8)                 /* 获取 DO 电平 */
#define IOCTL_DO_SET_PULSE              _IOW(IOCTL_DO_MAGIC, 8, struct pulse_t)     /* 配置 DO 脉冲参数 */
#define IOCTL_DO_START_PULSE            _IO(IOCTL_DO_MAGIC,  9)                     /* 开始 DO 脉冲 */
#define IOCTL_DO_STOP_PULSE             _IO(IOCTL_DO_MAGIC,  10)                    /* 停止 DO 脉冲 */

#define IOCTL_DO_CHK_ALL_LEVEL          _IOR(IOCTL_DO_MAGIC, 51, u32)               /* 核查 DO 所有通道电平 */
#define IOCTL_DO_CHK_MODE               _IOR(IOCTL_DO_MAGIC, 52, u8)                /* 核查 DO 模式 */
#define IOCTL_DO_CHK_TIMEOUT_STA        _IOR(IOCTL_DO_MAGIC, 53, u8)                /* 核查 DO 吸合超时状态 */
#define IOCTL_DO_CHK_TIMEOUT            _IOR(IOCTL_DO_MAGIC, 54, u8)                /* 核查 DO 吸合超时时间 */
#define IOCTL_DO_CHK_LEVEL              _IOR(IOCTL_DO_MAGIC, 55, u8)                /* 核查 DO 电平 */
#define IOCTL_DO_CHK_PULSE              _IOR(IOCTL_DO_MAGIC, 56, struct pulse_t)    /* 核查 DO 脉冲参数 */
#define IOCTL_DO_CHK_CMD                _IOR(IOCTL_DO_MAGIC, 57, u16)               /* 核查 DO 指令 */

#define IOCTL_DO_GET_DRV_VERSION        _IOR(IOCTL_DO_MAGIC, 101, u32)              /* 获取驱动版本号 */
#define IOCTL_DO_GET_FPGA_VERSION       _IOR(IOCTL_DO_MAGIC, 102, u32)              /* 获取 FPGA 版本号 */

enum do_cmd {
    DO_CMD_START        = 0x5555,       /* 开始 DO 脉冲指令 */
    DO_CMD_STOP         = 0x6666,       /* 停止 DO 脉冲指令 */
};

enum do_mode {
    DO_MOD_LEVEL        = 0,            /* 电平输出 */
    DO_MOD_PULSE        = 1,            /* 脉冲输出 */
};

enum do_timeout_t {
    DO_TIMEOUT_OFF  = 0,                /* 关闭吸合超时 */
    DO_TIMEOUT_ON   = 1,                /* 打开吸合超时 */
};

/* DO 设备 */
struct do_dev_t {
    void *parent;                       /* 父设备指针 */
    struct device *dev;                 /* 设备描述符 */
    struct mutex lock;                  /* 互斥锁 */
    char name[32];                      /* 设备名称 */
    u8 index;                           /* 索引号 */

    u8 mode;                            /* 模式 */
    u8 timeout_sta;                     /* 吸合超时状态 */
    u8 timeout_sec;                     /* 吸合超时时间, s */
    u8 set_level;                       /* 配置电平 */
    u8 get_level;                       /* 获取电平 */
    // u16 pulse_high;                     /* 脉冲高电平时间, ms */
    // u16 chk_pulse_high;                 /* 脉冲高电平时间获取值 */
    // u16 pulse_cycle;                    /* 脉冲周期时间, ms */
    // u16 chk_pulse_cycle;                /* 脉冲周期获取值 */
    // u32 pulse_num;                      /* 脉冲数量 */
    // u32 chk_pulse_num;                  /* 脉冲数量获取值 */
    struct pulse_t pulse;               /* 脉冲参数 */
    u8 pulse_sta;                       /* 脉冲状态, 0: 开始; 1: 停止 */

    u8 chk_mode;                        /* 模式获取值 */
    u8 chk_timeout_sta;                 /* 吸合超时状态 */
    u8 chk_timeout;                     /* 吸合超时时间 */
    u8 chk_level;                       /* 配置电平获取值 */
    struct pulse_t chk_pulse;           /* 脉冲参数 */
};

/* DO 控制器 */
struct do_ctrl_t {
    struct device *dev;                                                 /* 设备描述符 */
    struct mutex lock;                                                  /* 互斥锁 */
    char name[32];                                                      /* 设备名称 */
    u8 num;                                                             /* 设备数量 */

    struct pcie_dev_t *pcie_dev;                                        /* PCIe 设备指针 */
    u32 (*read_reg)(struct pcie_dev_t *pcie_dev, u32 reg);              /* 读寄存器 */
    void (*write_reg)(struct pcie_dev_t *pcie_dev, u32 reg, u32 val);   /* 写寄存器 */
    struct cdev_ctrl_t cdev_ctrl;                                       /* 字符设备控制器 */
    struct do_dev_t *gpo;                                               /* DO */

    u32 set_all_level;                                                  /* 配置所有通道电平 */
    u32 chk_all_level;                                                  /* 核查所有通道电平 */
    u32 get_all_level;                                                  /* 回读所有通道电平 */

    u32 drv_ver;                                                        /* 驱动版本号 */
    u32 fpga_ver;                                                       /* FPGA 版本号 */
};

/* 初始化 DO 控制器 */
int init_do_ctrl(struct pcie_dev_t *pcie_dev, struct cdev_dev_t *cdev_dev, 
                 struct do_ctrl_t *pctrl, struct do_dev_t *gpo, 
                 const char *ctrl_name, u8 dev_num);
/* 注销 DO 控制器 */
void exit_do_ctrl(struct do_ctrl_t *ctrl, u8 dev_num);

#endif /* _LINUX_DO_DEV_H */
